﻿using Modbus.Device;
using System.Net;
using System.Net.Sockets;

namespace Coater.Helper.Modbus
{
    public class ModbusTCPHelper : IModbusHelper
    {
        private TcpClient client;
        private IModbusMaster master;
        private string serverIp;
        private int port;
        private int TimeOut;

        public bool IsOpen
        {
            get
            {
                if (this.client != null && this.client.Connected)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public ModbusTCPHelper(string serverIp, int port, int TimeOut = 2)
        {
            this.serverIp = serverIp;
            this.port = port;
            this.TimeOut = TimeOut;
            Open();
        }

        public void Open()
        {
            try
            {
                if (this.client != null && this.client.Connected)
                {
                    this.client.Close();
                }
                this.client = new TcpClient();
                this.client.Connect(IPAddress.Parse(serverIp), port);
                this.master = ModbusIpMaster.CreateIp(this.client);
                this.master.Transport.WriteTimeout = TimeOut * 1000;
                this.master.Transport.ReadTimeout = TimeOut * 1000;
                this.master.Transport.WaitToRetryMilliseconds = 500;
                this.master.Transport.Retries = 3;
            }
            catch { }
        }

        public void Close()
        {
            if (this.client != null && this.client.Connected)
            {
                this.client.Close();
            }
            this.master = null;
        }

        /// <summary>
        /// 01 读取线圈
        /// </summary>
        public bool[] ReadCoils(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
        {
            try
            {
                return this.master.ReadCoils(slaveAddress, startAddress, numberOfPoints);
            }
            catch (Exception ex)
            {
                LogHelper.DebugLog.Debug("[ReadCoils] failed: " + ex.Message);
                LogHelper.ErrorLog.Error(ex);
                return Array.Empty<bool>();
            }
        }

        /// <summary>
        /// 05 写单个线圈
        /// </summary>
        public bool WriteSingleCoil(byte slaveAddress, ushort coilAddress, bool value)
        {
            try
            {
                this.master.WriteSingleCoil(slaveAddress, coilAddress, value);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.DebugLog.Debug("[WriteSingleCoil] failed: " + ex.Message);
                LogHelper.ErrorLog.Error(ex);
                return false;
            }
        }

        /// <summary>
        /// 0F 写多个线圈
        /// </summary>
        public bool WriteMultipleCoils(byte slaveAddress, ushort startAddress, bool[] data)
        {
            try
            {
                this.master.WriteMultipleCoils(slaveAddress, startAddress, data);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.DebugLog.Debug("[WriteMultipleCoils] failed: " + ex.Message);
                LogHelper.ErrorLog.Error(ex);
                return false;
            }
        }

        /// <summary>
        /// 02 读取离散量输入
        /// </summary>
        public bool[] ReadInputs(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
        {
            try
            {
                return this.master.ReadInputs(slaveAddress, startAddress, numberOfPoints);

            }
            catch (Exception ex)
            {
                LogHelper.DebugLog.Debug("[ReadInputs] failed: " + ex.Message);
                LogHelper.ErrorLog.Error(ex);
                return Array.Empty<bool>();
            }
        }

        /// <summary>
        /// 04 读取输入寄存器
        /// </summary>
        public byte[] ReadInputRegisters(byte slaveId, ushort start, ushort length)
        {
            try
            {
                ushort[] data = this.master.ReadInputRegisters(slaveId, start, length);

                List<byte> result = new List<byte>();
                foreach (var item in data)
                {
                    result.AddRange(BitConverter.GetBytes(item).Reverse());
                }
                return result.ToArray();
            }
            catch (Exception ex)
            {
                LogHelper.DebugLog.Debug("[ReadInputRegisters] failed: " + ex.Message);
                LogHelper.ErrorLog.Error(ex);
                return Array.Empty<byte>();
            }
        }

        /// <summary>
        /// 03 读保持寄存器
        /// </summary>
        public byte[] ReadHoldingRegisters(byte slaveId, ushort start, ushort length)
        {
            try
            {
                ushort[] data = this.master.ReadHoldingRegisters(slaveId, start, length);

                List<byte> result = new List<byte>();
                foreach (var item in data)
                {
                    result.AddRange(BitConverter.GetBytes(item).Reverse());
                }
                return result.ToArray();
            }
            catch (Exception ex)
            {
                LogHelper.DebugLog.Debug("[ReadHoldingRegisters] failed: " + ex.Message);
                LogHelper.ErrorLog.Error(ex);
                return Array.Empty<byte>();
            }
        }

        /// <summary>
        /// 06 写单个保持寄存器
        /// </summary>
        public bool WriteSingleRegister(byte slaveAddress, ushort registerAddress, ushort value)
        {
            try
            {
                this.master.WriteSingleRegister(slaveAddress, registerAddress, value);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.DebugLog.Debug("[WriteSingleRegister] failed: " + ex.Message);
                LogHelper.ErrorLog.Error(ex);
                return false;
            }
        }

        /// <summary>
        /// 10 写多个保持寄存器
        /// </summary>
        public bool WriteMultipleRegisters(byte slaveAddress, ushort startAddress, ushort[] data)
        {
            try
            {
                this.master.WriteMultipleRegisters(slaveAddress, startAddress, data);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.DebugLog.Debug("[WriteMultipleRegisters] failed: " + ex.Message);
                LogHelper.ErrorLog.Error(ex);
                return false;
            }
        }

    }
}
